#include "dialog.h"
#include "ui_dialog.h"
#include <QFile>
#include <QFileDialog>
#include <QFileInfo>
#include <QMessageBox>
#include <QTime>
#include <QRegExp>
#include <QRegExpValidator>
#include <QDebug>
#include <QScrollBar>

#define STRING_APP1_OFFSET_VALUE            "800"
#define STRING_APP1_FLAG                    "A5A5A5A5"
#define STRING_APP2_FLAG                    "B5B5B5B5"
#define STRING_FRAME_SIZE                   "200"
#define STRING_OUTNAME                      "file_name"


void Dialog::initUI()
{
    //设置图标
    Dialog::setWindowIcon(QIcon(":/res/res/logo.ico"));

    //隐藏？号，显示最小
    Qt::WindowFlags flags= this->windowFlags();
    setWindowFlags(flags&~Qt::WindowContextHelpButtonHint);
    setWindowFlags(flags& Qt::WindowMinimizeButtonHint);

    /* 控件初始 */

    // BOOT APP1 APP2文件打开路径
    ui->lineEditBoot->setPlaceholderText("点击右侧>>打开bin文件");
    ui->lineEditApp1->setPlaceholderText("点击右侧>>打开bin文件");
    ui->lineEditApp2->setPlaceholderText("点击右侧>>打开bin文件");

    // 生成文件保存路径
    ui->lineEditOutName->setPlaceholderText(STRING_OUTNAME);

    // 填充
    ui->rBtnFF->setChecked(1);
    ui->rBtn00->setChecked(0);

    // 模式 ：模式1 = BOOT + APP1 模式2 = APP1 + APP2
    ui->rBtnMode1->setChecked(1);
    ui->rBtnMode2->setChecked(0);

    // 偏移 APP1标志 APP2标志 帧大小
    ui->lineEditApp1Offset->setEnabled(true);
    ui->lineEditApp1Flag->setEnabled(false);
    ui->lineEditApp2Flag->setEnabled(false);
    ui->lineEditFrameSize->setEnabled(false);

    // 修改配置框规则
    QRegExp rx1("[0-9A-Fa-f]{1-8}$");//正则表达式,限制数字与字母的输入，只能输入8位数字与字母的组合
    QValidator *validator1 = new QRegExpValidator(rx1, ui->lineEditApp1Offset);
    ui->lineEditApp1Offset->setValidator(validator1);
    ui->lineEditApp1Offset->setText(STRING_APP1_OFFSET_VALUE);

    QRegExp rx2("[0-9A-Fa-f]{8}$");//正则表达式,限制数字与字母的输入，只能输入8位数字与字母的组合
    QValidator *validator2 = new QRegExpValidator(rx2, ui->lineEditApp1Flag);
    ui->lineEditApp1Flag->setValidator(validator2);
    ui->lineEditApp1Flag->setText(STRING_APP1_FLAG);

    QValidator *validator3 = new QRegExpValidator(rx2, ui->lineEditApp2Flag);
    ui->lineEditApp2Flag->setValidator(validator3);
    ui->lineEditApp2Flag->setText(STRING_APP2_FLAG);

    QValidator *validator4 = new QRegExpValidator(rx1, ui->lineEditFrameSize);
    ui->lineEditFrameSize->setValidator(validator4);
    ui->lineEditFrameSize->setText(STRING_FRAME_SIZE);

    setFixedSize(size());

    // 配置允许拖拉文件
    this->setAcceptDrops(true);
    ui->lineEditBoot->setAcceptDrops(true);
    ui->lineEditApp1->setAcceptDrops(true);
    ui->lineEditApp2->setAcceptDrops(true);

    // 修改
    //ui->plainTextEdit->setEnabled(false);
    QPalette pale = ui->plainTextEdit->palette();
    pale.setColor(QPalette::Text,Qt::gray);
    ui->plainTextEdit->setPalette(pale);

    ui->plainTextEdit->setStyleSheet("background-color:transparent");

    // 清空数据存储buf
    arrDataBoot.clear();
    arrDataApp1.clear();
    arrDataApp2.clear();

    newPath = QDir::currentPath();

}

/* 校验和 */
QString file_checksum(QByteArray arr)
{
    int checksum = 0;
    for(int i = 0; i<arr.size(); i++)
    {
        checksum += arr[i];
    }
    return QString::number(checksum,16);
}

/* Save the input file data */
bool Dialog::saveFileData(const QString &aFileName, QByteArray &array)
{
    QFile aFile(aFileName);
    if(!aFile.open(QIODevice::ReadOnly))
    {
        return false;
    }

    array.clear();
    array = aFile.readAll();

    aFile.close();
    return true;
}

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
    , ui(new Ui::Dialog)
{
    ui->setupUi(this);

    initUI();
}

Dialog::~Dialog()
{
    delete ui;
}

/* 拖动进入事件 */
void Dialog::dragEnterEvent(QDragEnterEvent *event)
{
    // 数据中是否包含URL
    if(event->mimeData()->hasUrls())
    {
        event->acceptProposedAction(); // 如果数据中包含URL，就接收动作
    }
    else
    {
        event->ignore();               // 如果数据中不包含URL，就忽略该事件
    }

}

// 放下事件
void Dialog::dropEvent(QDropEvent *event)
{
    // 获取MIME数据
    const QMimeData *mimeData = event->mimeData();

    //如果数据中包含URL
    if(mimeData->hasUrls())
    {
        // 获取URL列表
        QList<QUrl> urls = mimeData->urls();

        //将其中的第一个URL表示为本地文件路径
        // toLocalFile()转换未本地文件路径
        QString fileName = urls.at(0).toLocalFile();

        // 文件路径不为空
        if(!fileName.isEmpty())
        {
            if (ui->lineEditBoot->underMouse())
            {
                ui->lineEditBoot->setText(fileName);
                //show_log(filePath);
                saveFileData(fileName,this->arrDataBoot);
                ui->label_BootCheckSum->setText("0x"+file_checksum(this->arrDataBoot));
            }
            else if (ui->lineEditApp1->underMouse())
            {
                ui->lineEditApp1->setText(fileName);
                saveFileData(fileName,this->arrDataApp1);
                ui->label_App1CheckSum->setText("0x"+file_checksum(this->arrDataApp1));
            }
            else if (ui->lineEditApp2->underMouse())
            {
                ui->lineEditApp2->setText(fileName);
                saveFileData(fileName,this->arrDataApp2);
                ui->label_App2CheckSum->setText("0x"+file_checksum(this->arrDataApp2));
            }
            else {
                qInfo() << "拖入异常";
            }
        }
    }
}

//调用该函数做记录输出
void Dialog::show_log(QString str)
{
    QTime current = QTime::currentTime();
    QString time  = current.toString("hh:mm:ss:zzz ");
    //qDebug() << "当前时间为：" << current.toString("hh:mm:ss");
    ui->plainTextEdit->appendPlainText(time+str);

    QScrollBar *scrollbar = ui->plainTextEdit->verticalScrollBar();
    if(scrollbar)
    {
        scrollbar->setSliderPosition(scrollbar->maximum());
    }
}

//调用该函数做记录输出，可选择是否需要加时间
void Dialog::show_log(QString str, bool isShowTime)
{
    if(isShowTime)
    {
        QTime current = QTime::currentTime();
        QString time  = current.toString("hh:mm:ss:zzz ");
        //qDebug() << "当前时间为：" << current.toString("hh:mm:ss");
        ui->plainTextEdit->appendPlainText(time+str);
    }else
    {
        ui->plainTextEdit->appendPlainText(str);
    }

    QScrollBar *scrollbar = ui->plainTextEdit->verticalScrollBar();
    if(scrollbar)
    {
        scrollbar->setSliderPosition(scrollbar->maximum());
    }
}


/* 点击打开boot按钮 */
void Dialog::on_pBtnBoot_clicked()
{
    //QString curPath = QDir::currentPath();  //获取应用当前目录
    QString dlgTitle="选择文件";
    QString filter="bin文件(*.bin)";
    QString aFileName;
    QString path = ui->lineEditBoot->text();

    if(path.isEmpty())
    {
        path = newPath;
    }
    aFileName = QFileDialog::getOpenFileName(this,dlgTitle,path,filter);

    if(aFileName.isEmpty())
    {
        show_log("警告:文件为空");
        return;
    }

    //在文本上显示
    ui->lineEditBoot->setText(aFileName);

    saveFileData(aFileName,this->arrDataBoot);

    ui->label_BootCheckSum->setText("0x"+file_checksum(this->arrDataBoot));
}

/* 点击打开app1按钮 */
void Dialog::on_pushApp1_clicked()
{
    //QString curPath = QDir::currentPath();  //获取应用当前目录
    QString dlgTitle="选择文件";
    QString filter="bin文件(*.bin)";
    QString aFileName;
    QString path = ui->lineEditApp1->text();

    if(path.isEmpty())
    {
        path = newPath;
    }
    aFileName = QFileDialog::getOpenFileName(this,dlgTitle,path,filter);

    if(aFileName.isEmpty())
    {
        show_log("警告:文件为空");
        return;
    }

    //在文本上显示
    ui->lineEditApp1->setText(aFileName);
    //show_log(aFileName);

    saveFileData(aFileName,this->arrDataApp1);
    ui->label_App1CheckSum->setText("0x"+file_checksum(this->arrDataApp1));
}
/* 点击打开app2按钮 */
void Dialog::on_pushApp2_clicked()
{
    QString dlgTitle="选择文件";
    QString filter="bin文件(*.bin)";
    QString aFileName;
    QString path = ui->lineEditApp2->text();

    if(path.isEmpty())
    {
        path = newPath;
    }
    aFileName = QFileDialog::getOpenFileName(this,dlgTitle,path,filter);

    if(aFileName.isEmpty())
    {
        show_log("警告:文件为空");
        return;
    }

    //在文本上显示
    ui->lineEditApp2->setText(aFileName);

    saveFileData(aFileName,this->arrDataApp2);
    ui->label_App2CheckSum->setText("0x"+file_checksum(this->arrDataApp2));
}

/* 点击打开Output按钮 */
void Dialog::on_pBtnOutput_clicked()
{
    QString dlgTitle="选择保存目录";
    QString path = ui->lineEditOutput->text();
    QString saveDir;

    if(path.isEmpty())
    {
        path = newPath;
    }
    saveDir=QFileDialog::getExistingDirectory(this,dlgTitle,path,QFileDialog::ShowDirsOnly);

    if(!saveDir.isEmpty())
    {
        path = saveDir;
        newPath = path;

        show_log("保存路径已生成");
    }
    ui->lineEditOutput->setText(path);
}

/* 处理boot 和 app1的合并  */
bool Dialog::merge_boot_app1()
{
    QString outputFilePath;
    QString outputFileName;

    if(ui->lineEditOutName->text().isEmpty())
        outputFileName = STRING_OUTNAME;
    else
        outputFileName = ui->lineEditOutName->text();

    outputFileName += ".bin";
    outputFilePath = ui->lineEditOutput->text() + "/" + outputFileName;

    QFile aFile(outputFilePath);

    bool exist = QFile::exists(outputFilePath);

    //等同于换行
    show_log(" ",false);

    if(exist)
    {
        show_log("文件已存在，已删除重新新建");
        aFile.remove();
    }

    if(arrDataBoot.isEmpty()||arrDataBoot.size()==0)
    {
        show_log("警告:boot文件大小有误");

        return false;
    }

    //对app1的文件判断
    if(arrDataApp1.isEmpty()||arrDataApp1.size()==0)
    {
        show_log("警告:app1文件大小有误");
        return false;
    }

    if(ui->lineEditApp1Offset->text().isEmpty())
    {
        QMessageBox::information(this,"错误信息","请输入偏移数据(16进制)",QMessageBox::Ok,QMessageBox::NoButton);
        return false;
    }

    QString lineEditStr = ui->lineEditApp1Offset->text();

    bool ok;
    int offsetValue = lineEditStr.toInt(&ok,16);
    int bootSize    = arrDataBoot.size();
    int app1Size    = arrDataApp1.size();

    if(bootSize >= offsetValue)
    {
        QMessageBox::information(this,"错误信息","偏移地址必须大于boot文件大小",QMessageBox::Ok,QMessageBox::NoButton);
        show_log("警告:偏移地址存在boot文件区域");
        return false;
    }

    qDebug()<<lineEditStr<<" "<<offsetValue;

    QByteArray outputArray;
    outputArray.append(arrDataBoot);

    unsigned char fillData = 0x00;
    if(ui->rBtnFF->isChecked())
    {
        fillData = 0xFF;
    }

    unsigned int fillSize = offsetValue - bootSize;
    for(unsigned int i=0; i<fillSize; i++)
    {
        outputArray.insert(bootSize+i,fillData);
    }

    outputArray.append(arrDataApp1);

    //创建输出文件
    bool openOk = aFile.open(QIODevice::ReadWrite);
    if(openOk)
    {
        show_log("初始完成");
    }else
    {
        show_log("初始失败");
        return false;
    }

    if(aFile.write(outputArray))
    {
        int outputFileSize = outputArray.length();
        qDebug()<<outputFileSize;
        show_log("boot文件大小:" + QString::number(bootSize)+"(Byte)");
        show_log("app1文件大小:" + QString::number(app1Size)+"(Byte)");
        show_log("合并文件大小:" + QString::number(outputFileSize)+"(Byte)");
        show_log("生成文件名称:" + outputFileName + "," +  "校验和：0x" + file_checksum(outputArray));
    }
    aFile.close();

    return true;
}

/* 处理app1 和 app2的合并  */
bool Dialog::merge_app1_app2()
{
    QString lineEditStr;
    uint app1FlagValue,app2FlagValue,app1Size,app2Size,frameSize;

    bool ok;

    lineEditStr = ui->lineEditApp1Flag->text();
    app1FlagValue = lineEditStr.toUInt(&ok,16);
    qDebug()<<lineEditStr<<" "<<app1FlagValue;

    lineEditStr = ui->lineEditApp2Flag->text();
    app2FlagValue = lineEditStr.toUInt(&ok,16);
    qDebug()<<lineEditStr<<" "<<app2FlagValue;

    lineEditStr = ui->lineEditFrameSize->text();
    frameSize   = lineEditStr.toUInt(&ok,16);
    qDebug()<<lineEditStr<<" "<<frameSize;

    app1Size    = arrDataApp1.size();
    app2Size    = arrDataApp2.size();

    //对app1的文件判断
    if(arrDataApp1.isEmpty()||app1Size == 0)
    {
        show_log("警告:app1文件大小有误");
        return false;
    }
    //对app2的文件判断
    if(arrDataApp2.isEmpty()||app2Size == 0)
    {
        show_log("警告:app2文件大小有误");
        return false;
    }

    if(ui->lineEditApp1Offset->text().isEmpty())
    {
        QMessageBox::information(this,"错误信息","请输入偏移数据(16进制)",QMessageBox::Ok,QMessageBox::NoButton);
        return false;
    } 

    QString outputFilePath;
    QString outputFileName;

    if(ui->lineEditOutName->text().isEmpty())
        outputFileName = STRING_OUTNAME;
    else
        outputFileName = ui->lineEditOutName->text();

    outputFileName += ".bin";
    outputFilePath = ui->lineEditOutput->text() + "/" + outputFileName;

    QFile aFile(outputFilePath);

    bool exist = QFile::exists(outputFilePath);

    //等同于换行
    show_log(" ",false);

    if(exist)
    {
        show_log("文件已存在，已删除重新新建");
        aFile.remove();
    }

    QByteArray outputArray;

    uint tmpFlaveValue = app1FlagValue;

    for(int i=0;i<4;i++)
    {
        outputArray.append((tmpFlaveValue & 0xff000000)>>24);
        qDebug()<<((tmpFlaveValue & 0xff000000)>>24);
        tmpFlaveValue <<=8;
    }

    //选择填充选择00是FF
    unsigned char fillData = 0x00;
    if(ui->rBtnFF->isChecked())
    {
        fillData = 0xFF;
    }

    //填充凑齐一帧
    while(outputArray.size() % frameSize)
    {
        outputArray.append(fillData);
    }
    //插入app1文件数据
    outputArray.append(arrDataApp1);

    //填充凑齐一帧
    while(outputArray.size() % frameSize)
    {
        outputArray.append(fillData);
    }

    //插入app2标识
    tmpFlaveValue = app2FlagValue;
    for(int i=0;i<4;i++)
    {
        outputArray.append((tmpFlaveValue & 0xff000000)>>24);
        qDebug()<<((tmpFlaveValue & 0xff000000)>>24);
        tmpFlaveValue <<=8;
    }

    //填充凑齐一帧
    while(outputArray.size() % frameSize)
    {
        outputArray.append(fillData);
    }
    //插入app2文件数据
    outputArray.append(arrDataApp2);

    //int 正数最大 7FFFFFFF
    if(outputArray.size() > 0x7FFFFFFF)
    {
        show_log("警告:文件大小超过限制");
        return false;
    }

    //创建输出文件
    bool openOk = aFile.open(QIODevice::ReadWrite);
    if(openOk)
    {
        show_log("文件初始成功");
    }else
    {
        show_log("文件初始失败");
    }

    if(aFile.write(outputArray))
    {

        int outputFileSize = outputArray.length();
        qDebug()<<outputFileSize;
        show_log("app1文件大小:" + QString::number(app1Size)+"Byte");
        show_log("app2文件大小:" + QString::number(app2Size)+"Byte");
        show_log("生成文件大小:" + QString::number(outputFileSize)+"Byte");
        show_log("生成文件名称:" + outputFileName + "," + "校验和：0x" + file_checksum(outputArray));
    }
    aFile.close();

    return true;
}

/* 点击生成按钮响应 */
void Dialog::on_pBtnOk_clicked()
{
    bool mergeOk;

    if(ui->lineEditApp1->text().isEmpty())
    {
        QMessageBox::information(this,"错误信息","请打开app1的bin文件",QMessageBox::Ok,QMessageBox::NoButton);
        return;
    }

    if(ui->lineEditOutput->text().isEmpty())
    {
        QMessageBox::information(this,"错误信息","请选择保存的目录",QMessageBox::Ok,QMessageBox::NoButton);
        return;
    }

    if(ui->rBtnMode1->isChecked())
    {
        if(ui->lineEditBoot->text().isEmpty())
        {
            QMessageBox::information(this,"错误信息","请打开boot的bin文件",QMessageBox::Ok,QMessageBox::NoButton);
            return;
        }

        mergeOk = merge_boot_app1();

    }else if(ui->rBtnMode2->isChecked())
    {
        if(ui->lineEditApp2->text().isEmpty())
        {
            QMessageBox::information(this,"错误信息","请打开app2的bin文件",QMessageBox::Ok,QMessageBox::NoButton);
            return;
        }
        mergeOk = merge_app1_app2();
    }else
    {
        QMessageBox::information(this,"错误信息","请选择合并类型",QMessageBox::Ok,QMessageBox::NoButton);
        return;
    }

    if(mergeOk)
    {
        show_log("文件创建成功");
    }else
    {
        show_log("文件创建失败");
    }
}

/* 模式1选择 */
void Dialog::on_rBtnMode1_clicked(bool checked)
{
    ui->lineEditApp1Offset->setEnabled(checked);
    ui->lineEditApp1Flag->setEnabled(false);
    ui->lineEditApp2Flag->setEnabled(false);
    ui->lineEditFrameSize->setEnabled(false);
}

/* 模式2选择 */
void Dialog::on_rBtnMode2_clicked(bool checked)
{
    ui->lineEditApp1Offset->setEnabled(false);
    ui->lineEditApp1Flag->setEnabled(checked);
    ui->lineEditApp2Flag->setEnabled(checked);
    ui->lineEditFrameSize->setEnabled(checked);
}

